from random import sample

from django.contrib.auth.models import Group
from django.db.models import Q
from django.shortcuts import render

# Create your views here.
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST
from rest_framework.viewsets import ModelViewSet

from utils.permission import wrap_permisssion, TeacherPermission, RootPermission, ActiveUserPermission, auto_user, \
    ActiveUserPPermission
from .serializers import *
from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
from elasticsearch import Elasticsearch
from config.elasticSearchConfig import *

# 创建ES客户端对象，连接ES服务
es = Elasticsearch([{'host': HOST, 'port': PORT}])


# class TopicPageinationPageNumber(PageNumberPagination):
#     page_size = 3  # 默认每页多少条
#     page_query_param = 'P ' #浏览器传入标签名
#     page_size_query_param = 'size'  # 规定那个参数为分页大小参数 http://127.0.0.1:8002/work/topics/?P=1&size=5
#     max_page_size = 100  # 最大每页多少条

class TopicPageinationLimitOffset(LimitOffsetPagination): #分页器
    default_limit = 100  # 默认每页多少条
    max_limit = 100  # 最大每页多少条
    limit_query_param = 'L'  # 浏览器传入标签名


class LabelViewset(ModelViewSet):
    permission_classes = [IsAuthenticated]
    queryset = Label.objects.all()
    serializer_class = LabelSerializer

    @wrap_permisssion(TeacherPermission)
    @auto_user
    def create(self, request, *args, **kwargs):#创建试卷标签类型
        return ModelViewSet.create(self, request, *args, **kwargs)

    @wrap_permisssion(ActiveUserPPermission)
    @auto_user
    def update(self, request, *args, **kwargs):#更改/更新试卷标签
        return ModelViewSet.update(self, request, *args, **kwargs)

    @wrap_permisssion(RootPermission)
    def destroy(self, request, *args, **kwargs):#删除试卷标签类型
        return ModelViewSet.destroy(self, request, *args, **kwargs)


class TopicViewSet(ModelViewSet):
    permission_classes = [IsAuthenticated]
    queryset = Topic.objects.filter(is_delete=False)
    serializer_class = TopicSerializer
    # pagination_class = TopicPageinationPageNumber
    pagination_class = TopicPageinationLimitOffset

    def get_queryset(self): #重写获取查询集内容，不同的请求url 调用不用的方法
        if self.action in ['practice', 'random']:
            return Topic.objects.filter(Q(is_delete=False) & ~Q(label__name__contains='试卷'))
        return self.queryset

    def get_serializer(self, *args, **kwargs): #重写get序列化，不同的请求url调用不同的序列化器（字段，属性）
        if self.action in ['exam', 'random']:
            return TopicStudentSerializer(*args, **kwargs)
        return self.serializer_class(*args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def list(self, request, *args, **kwargs):#查所有的题目内容
        return ModelViewSet.list(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    def retrieve(self, request, *args, **kwargs):#查单一题目内容
        return ModelViewSet.retrieve(self, request, *args, **kwargs)

    @wrap_permisssion(TeacherPermission)
    @auto_user
    def create(self, request, *args, **kwargs):
        # 将数据创建到mysql中 持久化存储
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        res_data = serializer.data
        # 在es中建立索引文档数据
        es.index(index='topic', id=res_data['id'], body=res_data)
        return Response(res_data)

    @wrap_permisssion(ActiveUserPPermission)
    @auto_user
    def update(self, request, *args, **kwargs):
        try:
            topic = self.get_queryset().get(id=kwargs['pk'])
        except Topic.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        serializer = self.get_serializer(topic, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        res_data = serializer.data
        es.update(index='topic', id=res_data['id'], body={"doc": res_data})
        return Response(res_data)

    @wrap_permisssion(RootPermission)
    def destroy(self, request, *args, **kwargs):
        res_data = ModelViewSet.destroy(self, request, *args, **kwargs)
        es.delete(index='topic', id=kwargs['pk'])
        return res_data

    @action(methods=['get'], detail=False)
    def practice(self, request):
        return ModelViewSet.list(self, request)

    @action(methods=['get'], detail=True)
    def exam(self, request, pk):
        labels = Label.objects.filter(id=pk, name__contains='试卷').first()
        if not labels:
            return Response(status=HTTP_404_NOT_FOUND)
        topics = labels.topic_set.filter(is_delete=False)
        serializer = self.get_serializer(topics, many=True)
        return Response(serializer.data)

    # @action(methods=['get'],detail=False)
    # def random(self,request):
    #     try:
    #         size = int(request.query_params.get('size',3))
    #     except ValueError:
    #         return Response(status=HTTP_400_BAD_REQUEST)
    #
    #     pool = list(self.get_queryset())
    #     if len(pool) < size :
    #         return Response({'detail':'超出题目个数：%s'% len(pool)},status=HTTP_400_BAD_REQUEST)
    #     serializer = self.get_serializer(sample(pool,size),many=True)
    #     return Response(serializer.data)

    @action(methods=['get'], detail=False)
    def random(self, request):
        # 获取随机刷题题目个数
        try:
            size = int(request.query_params.get('size', 3))
        except ValueError:
            return Response(status=HTTP_400_BAD_REQUEST)

        # 获取查询集，随机抽取指定个数
        pool = list(self.get_queryset())
        # 判断要获取的随机题目个数是否超出题目总数，如果操作，则给出提示
        if len(pool) < size:
            return Response({'detail': '超出题目个数，题目总数为：%s' % len(pool)}, status=HTTP_400_BAD_REQUEST)

        # 序列化，返回
        serializer = self.get_serializer(sample(pool, size), many=True)
        return Response(serializer.data)

    @action(methods=['put'], detail=False)
    def inites(self, request):
        # 获取mysql中的题目数据
        serializer = self.get_serializer(self.get_queryset(), many=True)  # es中要json数据所以要序列化
        data = serializer.data
        # 传到es中
        for i in data:
            es.index(index='topic', id=i['id'], body=i)
        return Response(data)

    @action(methods=['get'], detail=False)
    def search(self, requeset):
        data = dict(requeset.query_params)  # 获取的是一个字典对象转成字典
        offset = int(data.get('offset', [0])[0])
        limit = int(data.get('limit', [3])[0])
        subject = data.get('subject', [''])[0]  # es匹配字符串信息，所以用索引取值，取到字符串

        # 判断用户身份信息 是否显示试卷内容
        user = requeset.user
        group = Group.objects.filter(name='老师').first()
        user_group = user.groups.all()
        work_user = user.is_superuser or group in user_group
        # work_user = False  # 用来测试用户权限可查看试卷

        query = {
            "query": {

            },
            "highlight": {
                "pre_tags": "<span style='color:red'>",
                "post_tags": "</span>",
                "fields": {
                    "subject": {}
                }
            },
            "from": offset,
            "size": limit
        }

        if work_user:
            # 是老师或者超级管理员
            if subject:
                query['query']['match'] = {
                    "subject": subject
                }
            else:
                query['query']['match_all'] = {}
        else:
            # 是学生
            if subject:
                query['query'] = {
                    "bool": {
                        "must": [
                            {
                                "match": {
                                    "subject": subject
                                }
                            },
                        ],
                        "must_not": [
                            {
                                "match_phrase": {
                                    "label_name": "试卷"
                                }
                            }
                        ]
                    }
                }
            else:
                query['query'] = {
                    "bool": {
                        "must_not": [
                            {
                                "match_phrase": {
                                    "label_name": "试卷"
                                }
                            }
                        ]
                    }
                }

        es_res = es.search(index='topic', body=query)
        count = es_res['hits']['total']['value']
        results = [self.highlight(i) for i in es_res['hits']['hits']]
        subject_url = f'subject={subject}&' if subject else ''
        next = f'{CLIENT}/work/topics/search/?{subject_url}limit={limit}&offset={offset + limit}' if offset + limit < count else None
        previvous = f'{CLIENT}/work/topics/search/?{subject_url}limit={limit}&offset={offset - limit}' if offset > 0 else None
        res = {
            "count": count,
            "next": next,
            "previvous": previvous,
            "results": results
        }
        return Response(res)

    def highlight(self, i):
        if i.get('highlight'):
            i['_source']['subject'] = i['highlight']['subject'][0]
        return i['_source']
